%s、%c、字符常量、字符串常量,const char*,指针数组,字符串数组总结

您所在的位置:网站首页 特许经营 本级国企 %s、%c、字符常量、字符串常量,const char*,指针数组,字符串数组总结

%s、%c、字符常量、字符串常量,const char*,指针数组,字符串数组总结

2023-08-04 16:36| 来源: 网络整理| 查看: 265

首先明确以下几点:

1.字符串是一个数组,C语言中没有字符串类型的,字符串是由字符元素组成的数组。

2.%s用于输出字符串类型的内容,%c输出单个字符。

3.一般讲到常量指针const char*,基本都是针对字符串的。比如const char* p=“abc"。(“abc”实际上是一个地址,所以应该赋值给一个指针变量。)当然,对字符常量,const chat* p=‘a’也可以,但是改语句的作用是把字符常量a的ASCII码赋值给指针变量p,这在实际应用中没有什么意义。

4.因为前几天一直纠缠于字符常量和字符串常量中,所以错误的理解成了const char* p='a',也是将字符常量a的地址给到指针变量p了。但要注意,单个的字符常量不是数组,只有涉及到数组时,才有指针变量时字符串常量首字符的存储地址这一说法,单个字符串不是数组,根本就没有什么‘a’表示字符常量a的存储地址这种说法!这和第二条也是相对应的。

就记住:const char*基本是和字符串,注意是字符串,是一个数组相对应的!

5.const char*是针对字符串来说的,const char* 变量名[ ],是指针数组,是一个“二级指针”,里面存储的是指针变量的地址,所以是二级指针。

6.字符串是一个字符数组,即使是"A",也是一个字符串,也应该用char s[ ]="A",而不是char s="A"。

7.只有对于数组,才有数组名为第一个元素所在地址,而且数组名是一个指针常量。也就是对于字符串,才有数组名是一个指针,对于单个的字符,不是数组,没有说字符变量名是一个地址的说法。

8.看一下,犯过错误。c语言中不能将字符串赋值给字符数组https://blog.csdn.net/tjh1998/article/details/114628498?utm_medium=distribute.pc_relevant.none-task-blog-2%7Edefault%7EBlogCommendFromBaidu%7Edefault-6.no_search_link&depth_1-utm_source=distribute.pc_relevant.none-task-blog-2%7Edefault%7EBlogCommendFromBaidu%7Edefault-6.no_search_link

下面看程序实例,关于更好的理解printf 输出字符、字符串,以及const char* 和字符串数组:

#include #include #define MAX 3 int main(int argc, char* agrv[]) { const char* a = 'a'; //a是一个字符常量,不是数组,这个语句的意思是把指针a赋值为字符'a'的ASCII码。 //const char* q = { "abc", "123" }; //这样写是不对的,这是字符串数组,应该是char* q[],这实际上是一个数组的数组,因为字符串本身就是数组。注意,数组元素就是要写成[]。 char* e = 'd';//此语句的含义也是把字符d的ASCII作为地址赋值给指针变量n //这样表达是不对的,因为'd'是单个字符,不是一个数组,没有说首个元素的地址什么的,这样写本身就是错误的。(本人比较喜欢重复说,哈哈) //字符串是一个数组 printf("************************************\n"); printf("%d\n", e);//输出的是字符d的ASCII码100,因为e的值是'd' // printf("%c\n", *e);//这个语句是不能执行的,这个语句的意思是给一个指针变量复制了字符 //常量'd'的ASCII地址,地址为字符d的ASCII码100的内存是不一定能被访问的。 /* 同样也就解释了之前的疑问,为什么const char*是针对字符串,而不是字符来说的呢, 因为单个字符是一个数组,没有说'a',就表示a这个常量字符的说法。而字符串是数组,有地址传递的这个概念。 当然,字符常量也是存储在系统管理的常量存储区中的。*/ // //=====================下面的程序是对于%s和%c的使用================================ printf("***************************\n"); // char* k = "abc";//(实际上就是const char* k="abc";) printf("pointer k is %p\n", k);//输出字符串abc的首地址 // printf("%s\n", *k); /*不能执行,因为k只是存储了字符串的首地址,*k实际上只是首字符a,单个字符不能用%s输出。*/ printf("%c\n", *k);//可以执行,输出首字母a printf("%s\n", k); /*输出字符串abc。这是产生了一个疑问,为什么k前面不用加取值符号*就可以输出字符串常量abc呢。如果是*k,指的其实是首字符a,如果再搭配%s,肯定是有错误的。而且printf输出%s形式的数据时,后面跟的量应该是字符串指针或者字符串数组名。对于字符数组,采用遍历循环的方式才能把每个字符依次输出。*/ printf("**********************\n"); //实际上,字符串数组名是一个二级指针,是指针的指针! const char* n[] = {"abcdef", "BC" }; //%s后面要跟一个指向字符串常量的一级指针 printf("%s\n", n[0]);//认为输出a,结果是abcdef,因为n[0]是字符串常量abcdef的首地址。 printf("%s\n", n);//乱码,这个n实际上是一个地址的地址,是一个二级指针,不是n[0] printf("%s\n", *n);//输出abcdef,相当于n[0],这也就是*数组名=数组第一个元素的值。 /* n[0]就明确表明了是n[]数组的第一个元素,与数组名n是不一样的,n表示的是n[0]的地址。 */ //下面验证一下: printf("数组名n的值:%p\n", n); printf("n[0]的地址 %p\n", &n[0]); printf("n[0]的值 %p\n", n[0]); printf("abcedf的地址:%p\n", "abcdef"); for (int i = 0; i < 2; i++) { printf("数组n %s\n", *(n + i)); /* 结果却是依次输出了abcdef和BC,字符串数组指针和字符串指针的使用是不同的,加了*后再输出才是字符串,不是单个字符 为什么呢,注意区分字符串和字符串数组,字符串数组的数组名实际上是一个二级指针,使用*解引用之后才是一个一级指针,才能搭配%s使用! */ } for (int i = 0; i < 2; i++) { printf("数组n %s\n", (n + i)); //这样输出是乱码,相当于输出的是第二个元素所在的地址 } printf("**********************\n"); printf("看看对于字符串能不能用指针一次性输出\n"); const char* g = "abcde"; printf("pointer g 表示的字符串:%s\n", g);//输出abcde printf("pointer g 表示的字符:%c\n", *g);//打印字符串的首字符a printf("%c\n", *"ABC");//A printf("%c\n", "ABC");//???没有什么意思,输出一个不知道什么的值 //下面需要看一下字符串数组在内存中的存储方式 const char* name[] = { "ABC", "BCD", "DEC" }; for (int i = 0; i < MAX; i++) { printf("数组name:\n name[%d]=%c\n", i, *(name[i])); //依次输出A、B、D } for (int i = 0; i < MAX; i++) { printf("数组name:\n name[%d]=%s\n", i, (name[i])); //依次输出ABC、BCD、DEC } printf("**********************\n"); //printf("%s\n", *("AB"));//wrong,程序不运行,%s不能搭配字符使用 //printf("%s\n", "A");//输出A printf("%c\n", *"AB");//A printf("%c\n", *"A");//A printf("%s\n", "ABC");//ABC printf("**********************\n"); char d[5] = "hello";//字符串本身就是一个数组 printf("%s\n", d);//乱码 hello后面跟一堆垃圾值,因为在分配的空间中没有结束字符\0 // 注:%s后面跟的,可以是字符串指针,或者字符数组名。 /* 字符串就是字符组成的数组,但是后面多了一个结束符号\0; 别字符串指针写多了,再写成char a="abc",应该是char a[]="abc"...*/ return 0; }

要注意字符串数组的数组名是一个“地址的地址”,要*之后才能搭配%s输出字符串,字符串指针const char* 直接搭配%s即可输出字符串。

以此类推,凡是指针数组,数组名都是相当于一个"二级指针",如果想用数组名输出数组元素时,使用解引用*后才得到一个一级指针。

如:

#include #include int main(int argc, char* agrv[]) { const char* names[] = { "a", "b", "c" }; for (int i = 0; i < 3; i++) { printf("name[%d]=%s\n", i, names[i]);//这是直接用数组元素输出各个数组成员,数组元素本身就是一级指针。 } //下面看一下如果用数组名输出各个数组元素,需要采用指针移位的方式,而且因为指针数组的数组名是相当于一个二级指针,要使用*进行解引用才可以。 const char* m[] = { "as", "bs", "cs" }; for (int i = 0; i < 3; i++) { printf("m[%d]=%s\n", i, *(m + i)); } //输出首字母 //可以看出,如果想要输出单个字符,%c后面配合的应该直接是字符变量或者字符指针的解引用。 //这与%s输出字符串是不同的,根本原因还是在于字符串本身就是数组,字符却不是一个数组。 const char* s[] = { "as", "bs", "cs" }; for (int i = 0; i < 3; i++) { printf("s[%d]=%c\n", i, **(s + i)); } return 0; }

其实说了这么多,关键就在于%s后面跟的应该是一级指针,如果用指针数组名输出数组元素,要解引用,使用*指针数组名,才能搭配%输出正确的字符串。如果直接使用指针数组的成员,也就是直接使用指向字符串的指针,那么直接%s,指针数组名[i]就可以了。实际上,数组名也是一个指针常量呢,其实就是一个地址,相当于%s,后面接的就是指向字符串的指针。

下面再运行一下这些程序看看结果,加深对指针,数组,数组名,字符以及字符串的认识。

#include #include int main(int argc, char* agrv[]) { int array[3] = { 1, 2, 3 }; int* arr = array; int size = sizeof(array)/sizeof(int); for (int i = 0; i < 3; i++) { printf("array[%d]=%d\n",i, *(arr+i)); printf("arrar[%d]=%d\n", i, *(array + i)); } char s[3][4] = { { "Abc" }, { "Bcd" }, { "Cde" } };//字符串数组其实是一个二维数组 char w[] = { 'A', 'B', 'C' }; char n[] = "abc"; //上面三个全都是在栈区中的,在栈区中放了这些字符。 char* ps[] = {s[0],s[1],s[2]}; /*指针数组才能指向字符串数组,一个单独的指针不能指向一个字符串数组!一个单独的指针只能指向一个字符串,字符串本身就是一个字符数组,所以一个指针变量只能指向一个数组,指向二维数组的应该是指针数组才可以*/ char* pw = w; char* pn = n; for (int i = 0; i < 3; i++) { printf("s[%d]=%s\n", i, *(s + i)); printf("s[%d]=%s\n", i, *(ps + i));//指针和数组名都有p+1指向下一个元素的用法,因为数组名本身也是一个指针常量 printf("s[%d]=%s\n", i, s[i]); printf("s[%d]=%s\n", i, ps[i]); printf("w[%d]=%c\n", i, *(w + i)); printf("w[%d]=%c\n", i, *(pw + i)); printf("n=%s\n", n); printf("n=%s\n", pn); printf("n[0]=%c\n", *pn); } return 0; }



【本文地址】


今日新闻


推荐新闻


CopyRight 2018-2019 办公设备维修网 版权所有 豫ICP备15022753号-3